#include "StdAfx.h"
#include "SkinnedInt.h"
#include "Common.h"

void CSkinnedInt::SetValue(int val)
{
  if (val < m_min)
    val = m_min;
  if (val > m_max)
    val = m_max;
  if (val != m_val)
  {
    m_val = val;
    if (m_hWnd)
      InvalidateRect(NULL, FALSE);

    SendMessage(::GetParent(m_hWnd), WM_INTVALUECHANGED, (WPARAM)m_val, (LPARAM)m_hWnd);
  }
}

void CSkinnedInt::Draw(CDCHandle dc, const CRect& rClip)
{
  CRect rcClient;
  GetClientRect(&rcClient);

  dc.FillRect(&rClip, CTheme::brWindowBg);

  CRect rc = rcClient;
  if (m_imgLeft.height < rc.Height())
  {
    rc.top += (rc.Height() - m_imgLeft.height) / 2;
    rc.bottom = rc.top + m_imgLeft.height;
  }
  rc.right = rc.left + m_imgLeft.width;
  m_imgLeft.Draw(dc, rc);

  rc = rcClient;
  if (m_imgRight.height < rc.Height())
  {
    rc.top += (rc.Height() - m_imgRight.height) / 2;
    rc.bottom = rc.top + m_imgRight.height;
  }
  rc.left = rc.right - m_imgRight.width;
  m_imgRight.Draw(dc, rc);

  rc = rcClient;
  rc.left  += m_imgLeft.width;
  rc.right -= m_imgRight.width;
  if (m_imgBg.height < rc.Height())
  {
    rc.top += (rc.Height() - m_imgBg.height) / 2;
    rc.bottom = rc.top + m_imgBg.height;
  }
  m_imgBg.Draw(dc, rc);

  CImage& bar = m_dragging ? m_imgBarDown : m_imgBar;
  rc.top = rcClient.top;
  rc.bottom = rcClient.bottom;
  if (bar.height < rc.Height())
  {
    rc.top += (rc.Height() - bar.height) / 2;
    rc.bottom = rc.top + bar.height;
  }
  int x = (m_val * (rc.Width() - bar.width)) / (m_max - m_min);
  rc.left += x;
  rc.right = rc.left + bar.width;
  bar.Draw(dc, rc);
}

void CSkinnedInt::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
  if (nRepCnt > 100)
    nRepCnt = 100;
  int d = nRepCnt * (m_max - m_min) / 1000 + 1;
  switch(nChar)
  {
  case VK_LEFT:
    SetValue(m_val - d);
    break;
  case VK_RIGHT:
    SetValue(m_val + d);
    break;
  }
}

void CSkinnedInt::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
}

void CSkinnedInt::OnLButtonDown(UINT nFlags, CPoint point)
{
  m_longTimerCnt = 0;
  m_dragging = false;
  m_tapLeft = false;
  m_tapRight = false;
  m_lastX = point.x;

  SetCapture();

  CRect rc = GetBarRect();
  if (IsPtInRect(point.x, point.y, rc))
  {
    m_dragging = true;
    return;
  }

  rc = GetLeftRect();
  if (IsPtInRect(point.x, point.y, rc))
  {
    SetValue(m_val - 1);
    m_longTimer.Start(LONG_TIMER_INTERVAL);
    m_tapLeft = true;
    return;
  }
  rc = GetRightRect();
  if (IsPtInRect(point.x, point.y, rc))
  {
    SetValue(m_val + 1);
    m_longTimer.Start(LONG_TIMER_INTERVAL);
    m_tapRight = true;
    return;
  }
}

void CSkinnedInt::OnMouseMove(UINT nFlags, CPoint point)
{
  if (m_dragging)
  {
    int dx = point.x - m_lastX;

    if (dx != 0)
    {
      CRect rc;
      GetClientRect(&rc);
      rc.left += m_imgLeft.width;
      rc.right -= m_imgRight.width;
      CImage& bar = m_dragging ? m_imgBarDown : m_imgBar;
      int val = ((point.x - rc.left) * (m_max - m_min)) / (rc.Width() - bar.width);
      SetValue(val);
    }

    m_lastX = point.x;
  }
  else if (m_tapLeft)
  {
    CRect rc = GetLeftRect();
    if (!IsPtInRect(point.x, point.y, rc))
      m_longTimer.Stop();
  }
  else if (m_tapRight)
  {
    CRect rc = GetLeftRect();
    if (!IsPtInRect(point.x, point.y, rc))
      m_longTimer.Stop();
  }
}

void CSkinnedInt::OnLButtonUp(UINT nFlags, CPoint point)
{
  ReleaseCapture();
  m_longTimer.Stop();
  m_dragging = false;
  m_tapLeft = false;
  m_tapRight = false;
}

RECT CSkinnedInt::GetBarRect()
{
  CRect rc;
  GetClientRect(&rc);

  CImage& bar = m_dragging ? m_imgBarDown : m_imgBar;
  if (bar.height < rc.Height())
  {
    rc.top += (rc.Height() - bar.height) / 2;
    rc.bottom = rc.top + bar.height;
  }
  rc.left += m_imgLeft.width;
  rc.right -= m_imgRight.width;

  int x = (m_val * (rc.Width() - bar.width)) / (m_max - m_min);

  rc.left += x;
  rc.right = rc.left + bar.width;

  return rc;
}

RECT CSkinnedInt::GetLeftRect()
{
  CRect rc;
  GetClientRect(&rc);

  if (m_imgLeft.height < rc.Height())
  {
    rc.top += (rc.Height() - m_imgLeft.height) / 2;
    rc.bottom = rc.top + m_imgLeft.height;
  }
  rc.right = rc.left + m_imgLeft.width;
  return rc;
}

RECT CSkinnedInt::GetRightRect()
{
  CRect rc;
  GetClientRect(&rc);

  if (m_imgRight.height < rc.Height())
  {
    rc.top += (rc.Height() - m_imgRight.height) / 2;
    rc.bottom = rc.top + m_imgRight.height;
  }
  rc.left = rc.right - m_imgRight.width;
  return rc;
}

bool CSkinnedInt::IsPtInRect(int x, int y, const CRect& rc)
{
  return x >= rc.left && x <= rc.right && y >= rc.top && y <= rc.bottom;
}

void CSkinnedInt::OnLongTimer(UINT nID, DWORD dwTime)
{
  if (m_longTimerCnt < 100)
    m_longTimerCnt++;

  int d = m_longTimerCnt * (m_max - m_min) / 1000 + 1;
  if (m_tapLeft)
    SetValue(m_val - d);
  else if (m_tapRight)
    SetValue(m_val + d);
}